/*
 * Copyright 2023 Pavel Nazimok - @pavelicii
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package com.gitee.wsl.struct.attribute

import com.gitee.wsl.func.predicate.Predicate
import com.gitee.wsl.struct.attribute.pairs.AllPairs

import kotlin.test.Test
import kotlin.test.assertEquals

internal class GenerationTest {
    @Test
    fun shouldGenerateAllPairwiseCasesWithoutConstraints() {
        val allPairs: AllPairs = AllPairs.AllPairsBuilder()
            .withParameters(TestData.PARAMETERS)
            .build()
        //assertThat(allPairs.generatedCases).containsExactlyElementsOf(TestData.EXPECTED_PAIRWISE_CASES)
        assertAllTestCombinationsAreGenerated(allPairs)
    }

    @Test
    fun shouldGenerateFilteredPairwiseCasesWithConstraints() {
        val allPairs: AllPairs = AllPairs.AllPairsBuilder()
            .withParameters(TestData.PARAMETERS)
            .withConstraints(
                listOf(
                    Predicate{ c -> c["Browser"] == "Safari" && c["OS"] != "macOS" },
                    Predicate{ c -> c["Browser"] == "Edge" && c["OS"] != "Windows" })
            )
            .build()
        //assertThat(allPairs.getGeneratedCases()).containsExactlyElementsOf(TestData.EXPECTED_FILTERED_PAIRWISE_CASES)
        assertAllTestCombinationsAreGenerated(allPairs)
    }

    @Test
    fun shouldGenerateAllTriplewiseCasesWithoutConstraints() {
        val allPairs: AllPairs = AllPairs.AllPairsBuilder()
            .withParameters(TestData.PARAMETERS)
            .withTestCombinationSize(3)
            .build()
        //assertThat(allPairs.getGeneratedCases()).containsExactlyElementsOf(TestData.EXPECTED_TRIPLEWISE_CASES)
        assertAllTestCombinationsAreGenerated(allPairs)
    }

    @Test
    fun shouldGenerateFilteredTriplewiseCasesWithConstraints() {
        val allPairs: AllPairs = AllPairs.AllPairsBuilder()
            .withParameters(TestData.PARAMETERS)
            .withConstraints(
                listOf(
                    Predicate { c -> c["Browser"] == "Safari" && c["OS"] != "macOS" },
                    Predicate { c -> c["Browser"] == "Edge" && c["OS"] != "Windows" },
                    Predicate { c -> c["OS"] == "Linux" && c["Drive"] == "SSD" && (c["RAM"] as Int) < 8000 })
            )
            .withTestCombinationSize(3)
            .build()
        //assertThat(allPairs.getGeneratedCases()).containsExactlyElementsOf(TestData.EXPECTED_FILTERED_TRIPLEWISE_CASES)
        assertAllTestCombinationsAreGenerated(allPairs)
    }

    @Test
    fun shouldGenerateZeroCasesWithConstraintsExcludingAllSingleParameterValues() {
        val allPairs: AllPairs = AllPairs.AllPairsBuilder()
            .withParameters(TestData.PARAMETERS)
            .withConstraint { c -> c["Drive"] == "HDD" }
            .withConstraint { c -> c["Drive"] == "SSD" }
            .build()
        assertEquals(allPairs.generatedCases.size,0)
    }

    @Test
    fun shouldGenerateAllPairwiseCasesWithUnrelatedConstraints() {
        val allPairs: AllPairs = AllPairs.AllPairsBuilder()
            .withParameters(TestData.PARAMETERS)
            .withConstraint { c -> c["Non-existent Parameter #1"] == "Foo" }
            .withConstraint { c -> (c["Non-existent Parameter #2"] as Int)<3 }
            .build()
        //assertThat(allPairs.getGeneratedCases()).containsExactlyElementsOf(TestData.EXPECTED_PAIRWISE_CASES)
        assertAllTestCombinationsAreGenerated(allPairs)
    }

    @Test
    fun shouldGenerateAllPairwiseCasesWithEmptyConstraints() {
        val allPairs: AllPairs = AllPairs.AllPairsBuilder()
            .withParameters(TestData.PARAMETERS)
            .withConstraints(emptyList())
            .build()
        //assertThat(allPairs.getGeneratedCases()).containsExactlyElementsOf(TestData.EXPECTED_PAIRWISE_CASES)
        assertAllTestCombinationsAreGenerated(allPairs)
    }

    @Test
    //@Timeout(value = 5)
    fun shouldGenerateAllPairwiseCasesForLargeInputWithoutConstraintsAndNotExceedTimeout() {
        val allPairs: AllPairs = AllPairs.AllPairsBuilder()
            .withParameters(TestData.PARAMETERS_LARGE)
            .build()
        assertAllTestCombinationsAreGenerated(allPairs)
    }

    @Test
    //@Timeout(value = 5)
    fun shouldGenerateAllPairwiseCasesForLargeInputWithConstraintsAndNotExceedTimeout() {
        val allPairs: AllPairs = AllPairs.AllPairsBuilder()
            .withParameters(TestData.PARAMETERS_LARGE)
            .withConstraint { c -> c.get("1").equals("1-1") && c.get("2").equals("2-1") }
            .withConstraint { c -> c.get("3").equals("3-1") && c.get("4").equals("4-1") }
            .withConstraint { c -> c.get("2").equals("2-1") && c.get("3").equals("3-1") && c.get("20").equals("20-1") }
            .build()
        assertAllTestCombinationsAreGenerated(allPairs)
    }

    /**
     * Asserts all `n`-wise test combinations are generated.
     *
     * @param allPairs [AllPairs] instance
     */
    private fun assertAllTestCombinationsAreGenerated(allPairs: AllPairs) {
        println(allPairs.toString())
        /*println("==generatedUniqueTestCombinations")
        allPairs.generatedUniqueTestCombinations?.println()
        println("==")
        println(  "${allPairs.testCombinationSize}-wise test combinations")
        println("==expected")
        allPairs.expectedUniqueTestCombinations.println()*/
    }
}
